class RequiredString:
    def __set_name__(self, owner, name):
        self.property_name = name

    def __get__(self, instance, owner):
        if instance is None:
            return self
        
        return instance.__dict__[self.property_name] or None
    
    def __set__(self, instance, value):
        if not isinstance(value, str):
            raise ValueError(f'The {self.property_name} must be a string')
        
        if len(value) == 0:
            raise ValueError(f'The {self.property_name} cannot be empty')
        
        instance.__dict__[self.property_name] = value

class Person:

    first_name = RequiredString()
    last_name = RequiredString()

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    # @property
    # def first_name(self):
    #     return self._first_name
    
    # @first_name.setter
    # def first_name(self, value):
    #     if not isinstance(value, str):
    #         raise ValueError('The first name must be a string')
        
    #     if len(value) == 0:
    #         raise ValueError('The first name cannot be empty')
        
    #     self._first_name = value

    # @property
    # def last_name(self):
    #     return self._last_name
    
    # @last_name.setter
    # def last_name(self, value):
    #     if not isinstance(value, str):
    #         raise ValueError('The first name must be a string')
        
    #     if len(value) == 0:
    #         raise ValueError('The first name cannot be empty')
        
    #     self._first_name = value

if __name__ == '__main__':

    person = Person("", "")
    